home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cool / ge_cool.lha / GE_COOL2.1 / cpp / cpp5.c < prev    next >
C/C++ Source or Header  |  1992-04-13  |  22KB  |  918 lines

  1. /*
  2.  
  3.  
  4.  Copyright (C) 1990 Texas Instruments Incorporated.
  5.  
  6.  Permission is granted to any individual or institution to use, copy, modify,
  7.  and distribute this software, provided that this complete copyright and
  8.  permission notice is maintained, intact, in all copies and supporting
  9.  documentation.
  10.  
  11.  Texas Instruments Incorporated provides this software "as is" without
  12.  express or implied warranty.
  13.  
  14.  
  15.  *                C P P 5 . C
  16.  *        E x p r e s s i o n   E v a l u a t i o n
  17.  *
  18.  * Edit History
  19.  * 31-Aug-84    MM    USENET net.sources release
  20.  * 04-Oct-84    MM    __LINE__ and __FILE__ must call ungetstring()
  21.  *            so they work correctly with token concatenation.
  22.  *            Added string formal recognition.
  23.  * 25-Oct-84    MM    "Short-circuit" evaluate #if's so that we
  24.  *            don't print unnecessary error messages for
  25.  *            #if !defined(FOO) && FOO != 0 && 10 / FOO ...
  26.  * 31-Oct-84    ado/MM    Added token concatenation
  27.  *  6-Nov-84    MM    Split from #define stuff, added sizeof stuff
  28.  * 19-Nov-84    ado    #if error returns TRUE for (sigh) compatibility
  29.  * 21-Oct-85    RMS    Rename `token' to `tokenbuf'
  30.  * 23-Oct-85    RMS    Treat undefined symbols as having value zero.
  31.  */
  32.  
  33. #include    <stdio.h>
  34. #include    <ctype.h>
  35. #include    "cppdef.h"
  36. #include    "cpp.h"
  37.  
  38. /*
  39.  * Evaluate an #if expression.
  40.  */
  41.  
  42. static char    *opname[] = {        /* For debug and error messages    */
  43. "end of expression", "val", "id",
  44.   "+",   "-",  "*",  "/",  "%",
  45.   "<<", ">>",  "&",  "|",  "^",
  46.   "==", "!=",  "<", "<=", ">=",  ">",
  47.   "&&", "||",  "?",  ":",  ",",
  48.   "unary +", "unary -", "~", "!",  "(",  ")", "(none)",
  49. };
  50.  
  51. /*
  52.  * opdope[] has the operator precedence:
  53.  *     Bits
  54.  *      7    Unused (so the value is always positive)
  55.  *    6-2    Precedence (000x .. 017x)
  56.  *    1-0    Binary op. flags:
  57.  *        01    The binop flag should be set/cleared when this op is seen.
  58.  *        10    The new value of the binop flag.
  59.  * Note:  Expected, New binop
  60.  * constant    0    1    Binop, end, or ) should follow constants
  61.  * End of line    1    0    End may not be preceeded by an operator
  62.  * binary    1    0    Binary op follows a value, value follows.
  63.  * unary    0    0    Unary op doesn't follow a value, value follows
  64.  *   (        0    0    Doesn't follow value, value or unop follows
  65.  *   )        1    1    Follows value.  Op follows.
  66.  */
  67.  
  68. static char    opdope[OP_MAX] = {
  69.   0001,                    /* End of expression        */
  70.   0002,                    /* Digit            */
  71.   0000,                    /* Letter (identifier)        */
  72.   0141, 0141, 0151, 0151, 0151,        /* ADD, SUB, MUL, DIV, MOD    */
  73.   0131, 0131, 0101, 0071, 0071,        /* ASL, ASR, AND,  OR, XOR    */
  74.   0111, 0111, 0121, 0121, 0121,    0121,    /*  EQ,  NE,  LT,  LE,  GE,  GT    */
  75.   0061, 0051, 0041, 0041, 0031,        /* ANA, ORO, QUE, COL, CMA    */
  76. /*
  77.  * Unary op's follow
  78.  */
  79.   0160, 0160, 0160, 0160,        /* NEG, PLU, COM, NOT        */
  80.   0170, 0013, 0023,            /* LPA, RPA, END        */
  81. };
  82. /*
  83.  * OP_QUE and OP_RPA have alternate precedences:
  84.  */
  85. #define    OP_RPA_PREC    0013
  86. #define OP_QUE_PREC    0034
  87.  
  88. /*
  89.  * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that
  90.  *    #if FOO != 0 && 10 / FOO ...
  91.  * doesn't generate an error message.  They are stored in optab.skip.
  92.  */
  93. #define S_ANDOR        2
  94. #define S_QUEST        1
  95.  
  96. typedef struct optab {
  97.     char    op;            /* Operator            */
  98.     char    prec;            /* Its precedence        */
  99.     char    skip;            /* Short-circuit: TRUE to skip    */
  100. } OPTAB;
  101. static int    evalue;            /* Current value from evallex()    */
  102.  
  103. #ifdef    nomacargs
  104. FILE_LOCAL int
  105. isbinary(op)
  106. register int    op;
  107. {
  108.     return (op >= FIRST_BINOP && op <= LAST_BINOP);
  109. }
  110.  
  111. FILE_LOCAL int
  112. isunary(op)
  113. register int    op;
  114. {
  115.     return (op >= FIRST_UNOP && op <= LAST_UNOP);
  116. }
  117. #else
  118. #define    isbinary(op)    (op >= FIRST_BINOP && op <= LAST_BINOP)
  119. #define    isunary(op)    (op >= FIRST_UNOP  && op <= LAST_UNOP)
  120. #endif
  121.  
  122. /*
  123.  * The following definitions are used to specify basic variable sizes.
  124.  */
  125.  
  126. #ifndef    S_CHAR
  127. #define    S_CHAR        (sizeof (char))
  128. #endif
  129. #ifndef    S_SINT
  130. #define    S_SINT        (sizeof (short int))
  131. #endif
  132. #ifndef    S_INT
  133. #define    S_INT        (sizeof (int))
  134. #endif
  135. #ifndef    S_LINT
  136. #define    S_LINT        (sizeof (long int))
  137. #endif
  138. #ifndef    S_FLOAT
  139. #define    S_FLOAT        (sizeof (float))
  140. #endif
  141. #ifndef    S_DOUBLE
  142. #define    S_DOUBLE    (sizeof (double))
  143. #endif
  144. #ifndef    S_PCHAR
  145. #define    S_PCHAR        (sizeof (char *))
  146. #endif
  147. #ifndef    S_PSINT
  148. #define    S_PSINT        (sizeof (short int *))
  149. #endif
  150. #ifndef    S_PINT
  151. #define    S_PINT        (sizeof (int *))
  152. #endif
  153. #ifndef    S_PLINT
  154. #define    S_PLINT        (sizeof (long int *))
  155. #endif
  156. #ifndef    S_PFLOAT
  157. #define    S_PFLOAT    (sizeof (float *))
  158. #endif
  159. #ifndef    S_PDOUBLE
  160. #define    S_PDOUBLE    (sizeof (double *))
  161. #endif
  162. #ifndef    S_PFPTR
  163. #define S_PFPTR        (sizeof (int (*)()))
  164. #endif
  165.  
  166. typedef struct types {
  167.     short    type;            /* This is the bit if        */
  168.     char    *name;            /* this is the token word    */
  169. } TYPES;
  170.  
  171. static TYPES basic_types[] = {
  172.     { T_CHAR,    "char",        },
  173.     { T_INT,    "int",        },
  174.     { T_FLOAT,    "float",    },
  175.     { T_DOUBLE,    "double",    },
  176.     { T_SHORT,    "short",    },
  177.     { T_LONG,    "long",        },
  178.     { T_SIGNED,    "signed",    },
  179.     { T_UNSIGNED,    "unsigned",    },
  180.     { 0,        NULL,        },    /* Signal end        */
  181. };
  182.  
  183. /*
  184.  * Test_table[] is used to test for illegal combinations.
  185.  */
  186. static short test_table[] = {
  187.     T_FLOAT | T_DOUBLE | T_LONG | T_SHORT,
  188.     T_FLOAT | T_DOUBLE | T_CHAR | T_INT,
  189.     T_FLOAT | T_DOUBLE | T_SIGNED | T_UNSIGNED,
  190.     T_LONG  | T_SHORT  | T_CHAR,
  191.     0                        /* end marker    */
  192. };
  193.  
  194. /*
  195.  * The order of this table is important -- it is also referenced by
  196.  * the command line processor to allow run-time overriding of the
  197.  * built-in size values.  The order must not be changed:
  198.  *    char, short, int, long, float, double (func pointer)
  199.  */
  200. SIZES size_table[] = {
  201.     { T_CHAR,    S_CHAR,        S_PCHAR        },    /* char        */
  202.     { T_SHORT,    S_SINT,        S_PSINT        },    /* short int    */
  203.     { T_INT,    S_INT,        S_PINT        },    /* int        */
  204.     { T_LONG,    S_LINT,        S_PLINT        },    /* long        */
  205.     { T_FLOAT,    S_FLOAT,    S_PFLOAT    },    /* float    */
  206.     { T_DOUBLE,    S_DOUBLE,    S_PDOUBLE    },    /* double    */
  207.     { T_FPTR,    0,        S_PFPTR        },    /* int (*())     */
  208.     { 0,    0,        0        },    /* End of table    */
  209. };
  210.  
  211. int
  212. eval()
  213. /*
  214.  * Evaluate an expression.  Straight-forward operator precedence.
  215.  * This is called from control() on encountering an #if statement.
  216.  * It calls the following routines:
  217.  * evallex    Lexical analyser -- returns the type and value of
  218.  *        the next input token.
  219.  * evaleval    Evaluate the current operator, given the values on
  220.  *        the value stack.  Returns a pointer to the (new)
  221.  *        value stack.
  222.  * For compatiblity with older cpp's, this return returns 1 (TRUE)
  223.  * if a syntax error is detected.
  224.  */
  225. {
  226.     register int    op;        /* Current operator        */
  227.     register int    *valp;        /* -> value vector        */
  228.     register OPTAB    *opp;        /* Operator stack        */
  229.     int        prec;        /* Op precedence        */
  230.     int        binop;        /* Set if binary op. needed    */
  231.     int        op1;        /* Operand from stack        */
  232.     int        skip;        /* For short-circuit testing    */
  233.     int        value[NEXP];    /* Value stack            */
  234.     OPTAB        opstack[NEXP];    /* Operand stack        */
  235.     extern int    *evaleval();    /* Does actual evaluation    */
  236.  
  237.     valp = value;
  238.     opp = opstack;
  239.     opp->op = OP_END;        /* Mark bottom of stack        */
  240.     opp->prec = opdope[OP_END];    /* And its precedence        */
  241.     opp->skip = 0;            /* Not skipping now        */
  242.     binop = 0;
  243. again:    ;
  244. #ifdef    DEBUG_EVAL
  245.     printf("In #if at again: skip = %d, binop = %d, line is: %s",
  246.         opp->skip, binop, infile->bptr);
  247. #endif
  248.     if ((op = evallex(opp->skip)) == OP_SUB && binop == 0)
  249.         op = OP_NEG;            /* Unary minus        */
  250.     else if (op == OP_ADD && binop == 0)
  251.         op = OP_PLU;            /* Unary plus        */
  252.     else if (op == OP_FAIL)
  253.         return (1);                /* Error in evallex    */
  254. #ifdef    DEBUG_EVAL
  255.     printf("op = %s, opdope = %03o, binop = %d, skip = %d\n",
  256.         opname[op], opdope[op], binop, opp->skip);
  257. #endif
  258.     if (op == DIG) {            /* Value?        */
  259.         if (binop != 0) {
  260.         cerror("misplaced constant in #if", NULLST);
  261.         return (1);
  262.         }
  263.         else if (valp >= &value[NEXP-1]) {
  264.         cerror("#if value stack overflow", NULLST);
  265.         return (1);
  266.         }
  267.         else {
  268. #ifdef    DEBUG_EVAL
  269.         printf("pushing %d onto value stack[%d]\n",
  270.             evalue, valp - value);
  271. #endif
  272.         *valp++ = evalue;
  273.         binop = 1;
  274.         }
  275.         goto again;
  276.     }
  277.     else if (op > OP_END) {
  278.         cerror("Illegal #if line", NULLST);
  279.         return (1);
  280.     }
  281.     prec = opdope[op];
  282.     if (binop != (prec & 1)) {
  283.         cerror("Operator %s in incorrect context", opname[op]);
  284.         return (1);
  285.     }
  286.     binop = (prec & 2) >> 1;
  287.     for (;;) {
  288. #ifdef    DEBUG_EVAL
  289.         printf("op %s, prec %d., stacked op %s, prec %d, skip %d\n",
  290.         opname[op], prec, opname[opp->op], opp->prec, opp->skip);
  291. #endif
  292.         if (prec > opp->prec) {
  293.         if (op == OP_LPA)
  294.             prec = OP_RPA_PREC;
  295.         else if (op == OP_QUE)
  296.             prec = OP_QUE_PREC;
  297.         op1 = opp->skip;        /* Save skip for test    */
  298.         /*
  299.          * Push operator onto op. stack.
  300.          */
  301.         opp++;
  302.         if (opp >= &opstack[NEXP]) {
  303.             cerror("expression stack overflow at op \"%s\"",
  304.             opname[op]);
  305.             return (1);
  306.         }
  307.         opp->op = op;
  308.         opp->prec = prec;
  309.         skip = (valp>value) && (valp[-1] != 0);/*Short-circuit tester*/
  310.         /*
  311.          * Do the short-circuit stuff here.  Short-circuiting
  312.          * stops automagically when operators are evaluated.
  313.          */
  314.         if ((op == OP_ANA && !skip)
  315.          || (op == OP_ORO && skip))
  316.             opp->skip = S_ANDOR;    /* And/or skip starts    */
  317.         else if (op == OP_QUE)        /* Start of ?: operator    */
  318.             opp->skip = (op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0);
  319.         else if (op == OP_COL) {    /* : inverts S_QUEST    */
  320.             opp->skip = (op1 & S_ANDOR)
  321.                   | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST);
  322.         }
  323.         else {                /* Other ops leave    */
  324.             opp->skip = op1;        /*  skipping unchanged.    */
  325.         }
  326. #ifdef    DEBUG_EVAL
  327.         printf("stacking %s, valp[-1] == %d at %s",
  328.             opname[op], valp[-1], infile->bptr);
  329.         dumpstack(opstack, opp, value, valp);
  330. #endif
  331.         goto again;
  332.         }
  333.         /*
  334.          * Pop operator from op. stack and evaluate it.
  335.          * End of stack and '(' are specials.
  336.          */
  337.         skip = opp->skip;            /* Remember skip value    */
  338.         switch ((op1 = opp->op)) {        /* Look at stacked op    */
  339.         case OP_END:            /* Stack end marker    */
  340.         if (op == OP_EOE)
  341.             return (valp[-1]);        /* Finished ok.        */
  342.         goto again;            /* Read another op.    */
  343.  
  344.         case OP_LPA:            /* ( on stack        */
  345.         if (op != OP_RPA) {        /* Matches ) on input    */
  346.             cerror("unbalanced paren's, op is \"%s\"", opname[op]);
  347.             return (1);
  348.         }
  349.         opp--;                /* Unstack it        */
  350.         /* goto again;            -- Fall through        */
  351.  
  352.         case OP_QUE:
  353.         goto again;            /* Evaluate true expr.    */
  354.  
  355.         case OP_COL:            /* : on stack.        */
  356.         opp--;                /* Unstack :        */
  357.         if (opp->op != OP_QUE) {    /* Matches ? on stack?    */
  358.             cerror("Misplaced '?' or ':', previous operator is %s",
  359.             opname[opp->op]);
  360.             return (1);
  361.         }
  362.         /*
  363.          * Evaluate op1.
  364.          */
  365.         default:                /* Others:        */
  366.         opp--;                /* Unstack the operator    */
  367. #ifdef    DEBUG_EVAL
  368.         printf("Stack before evaluation of %s\n", opname[op1]);
  369.         dumpstack(opstack, opp, value, valp);
  370. #endif
  371.         valp = evaleval(valp, op1, skip);
  372. #ifdef    DEBUG_EVAL
  373.         printf("Stack after evaluation\n");
  374.         dumpstack(opstack, opp, value, valp);
  375. #endif
  376.         }                    /* op1 switch end    */
  377.     }                    /* Stack unwind loop    */
  378. }
  379.  
  380. FILE_LOCAL int
  381. evallex(skip)
  382. int        skip;        /* TRUE if short-circuit evaluation    */
  383. /*
  384.  * Return next eval operator or value.  Called from eval().  It
  385.  * calls a special-purpose routines for 'char' strings and
  386.  * numeric values:
  387.  * evalchar    called to evaluate 'x'
  388.  * evalnum    called to evaluate numbers.
  389.  */
  390. {
  391.     register int    c, c1, t;
  392.  
  393. again:                      /* Collect the token    */
  394.     c = skipws();
  395.     if ((c = macroid(c)) == EOF_CHAR || c == '\n') {
  396.       unget();
  397.       return (OP_EOE);        /* End of expression    */
  398.     }
  399.     t = type[c];
  400.     if (t == INV) {                /* Total nonsense    */
  401.         if (!skip) {
  402.         if (isascii(c) && isprint(c))
  403.             cierror("illegal character '%c' in #if", c);
  404.         else
  405.             cierror("illegal character (%d decimal) in #if", c);
  406.         }
  407.         return (OP_FAIL);
  408.     }
  409.     else if (t == QUO) {            /* ' or "        */
  410.         if (c == '\'') {            /* Character constant    */
  411.         evalue = evalchar(skip);    /* Somewhat messy    */
  412. #ifdef    DEBUG_EVAL
  413.         printf("evalchar returns %d.\n", evalue);
  414. #endif
  415.         return (DIG);            /* Return a value    */
  416.         }
  417.         cerror("Can't use a string in an #if", NULLST);
  418.         return (OP_FAIL);
  419.     }
  420.     else if (t == LET) {            /* ID must be a macro    */
  421.         if (streq(tokenbuf, "defined")) {    /* Or defined name    */
  422.         c1 = c = skipws();
  423.         if (c == '(')            /* Allow defined(name)    */
  424.             c = skipws();
  425.         if (type[c] == LET) {
  426.             evalue = (lookid(c) != NULL);
  427.             if (c1 != '('        /* Need to balance    */
  428.              || skipws() == ')')    /* Did we balance?    */
  429.             return (DIG);        /* Parsed ok        */
  430.         }
  431.         cerror("Bad #if ... defined() syntax", NULLST);
  432.         return (OP_FAIL);
  433.         }
  434.         else if (streq(tokenbuf, "sizeof"))    /* New sizeof hackery    */
  435.         return (dosizeof());        /* Gets own routine    */
  436.         evalue = 0;
  437.         return (DIG);
  438.     }
  439.     else if (t == DIG) {            /* Numbers are harder    */
  440.         evalue = evalnum(c);
  441. #ifdef    DEBUG_EVAL
  442.         printf("evalnum returns %d.\n", evalue);
  443. #endif
  444.     }
  445.     else if (t == SPA) {
  446.       goto again;
  447.     }
  448.     else if (strchr("=<>&|\\!", c) != NULL) {
  449.         /*
  450.          * Process a possible multi-byte lexeme.
  451.          */
  452.         c1 = cget();            /* Peek at next char    */
  453.         switch (c) {
  454.         case '!':
  455.         if (c1 == '=')
  456.             return (OP_NE);
  457.         break;
  458.  
  459.         case '=':
  460.         if (c1 != '=') {        /* Can't say a=b in #if    */
  461.             unget();
  462.             cerror("= not allowed in #if", NULLST);
  463.             return (OP_FAIL);
  464.         }
  465.         return (OP_EQ);
  466.  
  467.         case '>':
  468.         case '<':
  469.         if (c1 == c)
  470.             return ((c == '<') ? OP_ASL : OP_ASR);
  471.         else if (c1 == '=')
  472.             return ((c == '<') ? OP_LE  : OP_GE);
  473.         break;
  474.  
  475.         case '|':
  476.         case '&':
  477.         if (c1 == c)
  478.             return ((c == '|') ? OP_ORO : OP_ANA);
  479.         break;
  480.  
  481.         case '\\':
  482.         if (c1 == '\n')            /* Multi-line if    */
  483.             goto again;
  484.         cerror("Unexpected \\ in #if", NULLST);
  485.         return (OP_FAIL);
  486.         }
  487.         unget();
  488.     }
  489.     return (t);
  490. }
  491.  
  492. FILE_LOCAL int
  493. dosizeof()
  494. /*
  495.  * Process the sizeof (basic type) operation in an #if string.
  496.  * Sets evalue to the size and returns
  497.  *    DIG        success
  498.  *    OP_FAIL        bad parse or something.
  499.  */
  500. {
  501.     register int    c;
  502.     register TYPES    *tp;
  503.     register SIZES    *sizp;
  504.     register short    *testp;
  505.     short        typecode;
  506.  
  507.     if ((c = skipws()) != '(')
  508.         goto nogood;
  509.     /*
  510.      * Scan off the tokens.
  511.      */
  512.     typecode = 0;
  513.     while ((c = skipws())) {
  514.         if ((c = macroid(c)) == EOF_CHAR || c == '\n')
  515.         goto nogood;            /* End of line is a bug    */
  516.         else if (c == '(') {        /* thing (*)() func ptr    */
  517.         if (skipws() == '*'
  518.          && skipws() == ')') {        /* We found (*)        */
  519.             if (skipws() != '(')    /* Let () be optional    */
  520.             unget();
  521.             else if (skipws() != ')')
  522.             goto nogood;
  523.             typecode |= T_FPTR;        /* Function pointer    */
  524.         }
  525.         else {                /* Junk is a bug    */
  526.             goto nogood;
  527.         }
  528.         }
  529.         else if (type[c] != LET)        /* Exit if not a type    */
  530.         break;
  531.         else {                    /* Maybe combine tokens    */
  532.         /*
  533.          * Look for this unexpandable token in basic_types.
  534.          * The code accepts "int long" as well as "long int"
  535.          * which is a minor bug as bugs go (and one shared with
  536.          * a lot of C compilers).
  537.          */
  538.         for (tp = basic_types; tp->name != NULLST; tp++) {
  539.             if (streq(tokenbuf, tp->name))
  540.             break;
  541.         }
  542.         if (tp->name == NULLST) {
  543.             cerror("#if sizeof, unknown type \"%s\"", tokenbuf);
  544.             return (OP_FAIL);
  545.         }
  546.         typecode |= tp->type;        /* Or in the type bit    */
  547.         }
  548.     }
  549.     /*
  550.      * We are at the end of the type scan.  Chew off '*' if necessary.
  551.      */
  552.     if (c == '*') {
  553.         typecode |= T_PTR;
  554.         c = skipws();
  555.     }
  556.     if (c == ')') {                /* Last syntax check    */
  557.         for (testp = test_table; *testp != 0; testp++) {
  558.         if (!bittest(typecode & *testp)) {
  559.             cerror("#if ... sizeof: illegal type combination", NULLST);
  560.             return (OP_FAIL);
  561.         }
  562.         }
  563.         /*
  564.          * We assume that all function pointers are the same size:
  565.          *        sizeof (int (*)()) == sizeof (float (*)())
  566.          * We assume that signed and unsigned don't change the size:
  567.          *        sizeof (signed int) == (sizeof unsigned int)
  568.          */
  569.         if ((typecode & T_FPTR) != 0)    /* Function pointer    */
  570.         typecode = T_FPTR | T_PTR;
  571.         else {                /* Var or var * datum    */
  572.         typecode &= ~(T_SIGNED | T_UNSIGNED);
  573.         if ((typecode & (T_SHORT | T_LONG)) != 0)
  574.             typecode &= ~T_INT;
  575.         }
  576.         if ((typecode & ~T_PTR) == 0) {
  577.         cerror("#if sizeof() error, no type specified", NULLST);
  578.         return (OP_FAIL);
  579.         }
  580.         /*
  581.          * Exactly one bit (and possibly T_PTR) may be set.
  582.          */
  583.         for (sizp = size_table; sizp->bits != 0; sizp++) {
  584.         if ((typecode & ~T_PTR) == sizp->bits) {
  585.             evalue = ((typecode & T_PTR) != 0)
  586.             ? sizp->psize : sizp->size;
  587.             return (DIG);
  588.         }
  589.         }                    /* We shouldn't fail    */
  590.         cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode);
  591.         return (OP_FAIL);
  592.     }
  593.  
  594. nogood:    unget();
  595.     cerror("#if ... sizeof() syntax error", NULLST);
  596.     return (OP_FAIL);
  597. }
  598.  
  599. FILE_LOCAL int
  600. bittest(value)
  601. /*
  602.  * TRUE if value is zero or exactly one bit is set in value.
  603.  */
  604. {
  605. #if (4096 & ~(-4096)) == 0
  606.     return ((value & ~(-value)) == 0);
  607. #else
  608.     /*
  609.      * Do it the hard way (for non 2's complement machines)
  610.      */
  611.     return (value == 0 || value ^ (value - 1) == (value * 2 - 1));
  612. #endif
  613. }
  614.  
  615. FILE_LOCAL int
  616. evalnum(c)
  617. register int    c;
  618. /*
  619.  * Expand number for #if lexical analysis.  Note: evalnum recognizes
  620.  * the unsigned suffix, but only returns a signed int value.
  621.  */
  622. {
  623.     register int    value;
  624.     register int    base;
  625.     register int    c1;
  626.  
  627.     if (c != '0')
  628.         base = 10;
  629.     else if ((c = cget()) == 'x' || c == 'X') {
  630.         base = 16;
  631.         c = cget();
  632.     }
  633.     else base = 8;
  634.     value = 0;
  635.     for (;;) {
  636.         c1 = c;
  637.         if (isascii(c) && isupper(c1))
  638.         c1 = tolower(c1);
  639.         if (c1 >= 'a' && c1 <= 'f')
  640.         c1 -= ('a' - 10);
  641.         else c1 -= '0';
  642.         if (c1 < 0 || c1 >= base)
  643.         break;
  644.         value *= base;
  645.         value += c1;
  646.         c = cget();
  647.     }
  648.     if (c == 'u' || c == 'U')    /* Unsigned nonsense        */
  649.         c = cget();
  650.     unget();
  651.     return (value);
  652. }
  653.  
  654. FILE_LOCAL int
  655. evalchar(skip)
  656. int        skip;        /* TRUE if short-circuit evaluation    */
  657. /*
  658.  * Get a character constant
  659.  */
  660. {
  661.     register int    c;
  662.     register int    value;
  663.     register int    count;
  664.  
  665.     instring = TRUE;
  666.     if ((c = cget()) == '\\') {
  667.         switch ((c = cget())) {
  668.         case 'a':                /* New in Standard    */
  669. #if ('a' == '\a' || '\a' == ALERT)
  670.         value = ALERT;            /* Use predefined value    */
  671. #else
  672.         value = '\a';            /* Use compiler's value    */
  673. #endif
  674.         break;
  675.  
  676.         case 'b':
  677.         value = '\b';
  678.         break;
  679.  
  680.         case 'f':
  681.         value = '\f';
  682.         break;
  683.  
  684.         case 'n':
  685.         value = '\n';
  686.         break;
  687.  
  688.         case 'r':
  689.         value = '\r';
  690.         break;
  691.  
  692.         case 't':
  693.         value = '\t';
  694.         break;
  695.  
  696.         case 'v':                /* New in Standard    */
  697. #if ('v' == '\v' || '\v' == VT)
  698.         value = VT;            /* Use predefined value    */
  699. #else
  700.         value = '\v';            /* Use compiler's value    */
  701. #endif
  702.         break;
  703.  
  704.         case 'x':                /* '\xFF'        */
  705.         count = 3;
  706.         value = 0;
  707.         while ((((c = get()) >= '0' && c <= '9')
  708.              || (c >= 'a' && c <= 'f')
  709.              || (c >= 'A' && c <= 'F'))
  710.             && (--count >= 0)) {
  711.             value *= 16;
  712.             value += (c >= '0' && c <= '9') ?
  713.               (c - '0') : ((c & 0xF) + 9);
  714.         }
  715.         unget();
  716.         break;
  717.  
  718.         default:
  719.         if (c >= '0' && c <= '7') {
  720.             count = 3;
  721.             value = 0;
  722.             while (c >= '0' && c <= '7' && --count >= 0) {
  723.             value *= 8;
  724.             value += (c - '0');
  725.             c = get();
  726.             }
  727.             unget();
  728.         }
  729.         else value = c;
  730.         break;
  731.         }
  732.     }
  733.     else if (c == '\'')
  734.         value = 0;
  735.     else value = c;
  736.     /*
  737.      * We warn on multi-byte constants and try to hack
  738.      * (big|little)endian machines.
  739.      */
  740. #if BIG_ENDIAN
  741.     count = 0;
  742. #endif
  743.     while ((c = get()) != '\'' && c != EOF_CHAR && c != '\n') {
  744.         if (!skip)
  745.         ciwarn("multi-byte constant '%c' isn't portable", c);
  746. #if BIG_ENDIAN
  747.         count += BITS_CHAR;
  748.         value += (c << count);
  749. #else
  750.         value <<= BITS_CHAR;
  751.         value += c;
  752. #endif
  753.     }
  754.     instring = FALSE;
  755.     return (value);
  756. }
  757.  
  758. FILE_LOCAL int *
  759. evaleval(valp, op, skip)
  760. register int    *valp;
  761. int        op;
  762. int        skip;        /* TRUE if short-circuit evaluation    */
  763. /*
  764.  * Apply the argument operator to the data on the value stack.
  765.  * One or two values are popped from the value stack and the result
  766.  * is pushed onto the value stack.
  767.  *
  768.  * OP_COL is a special case.
  769.  *
  770.  * evaleval() returns the new pointer to the top of the value stack.
  771.  */
  772. {
  773.     register int    v1, v2;
  774.  
  775.     if (isbinary(op))
  776.         v2 = *--valp;
  777.     v1 = *--valp;
  778. #ifdef    DEBUG_EVAL
  779.     printf("%s op %s", (isbinary(op)) ? "binary" : "unary",
  780.         opname[op]);
  781.     if (isbinary(op))
  782.         printf(", v2 = %d.", v2);
  783.     printf(", v1 = %d.\n", v1);
  784. #endif
  785.     switch (op) {
  786.     case OP_EOE:
  787.          break;
  788.  
  789.     case OP_ADD:
  790.         v1 += v2;
  791.         break;
  792.  
  793.     case OP_SUB:
  794.         v1 -= v2;
  795.         break;
  796.  
  797.     case OP_MUL:
  798.         v1 *= v2;
  799.         break;
  800.  
  801.     case OP_DIV:
  802.     case OP_MOD:
  803.         if (v2 == 0) {
  804.         if (!skip) {
  805.             cwarn("%s by zero in #if, zero result assumed",
  806.             (op == OP_DIV) ? "divide" : "mod");
  807.         }
  808.         v1 = 0;
  809.         }
  810.         else if (op == OP_DIV)
  811.         v1 /= v2;
  812.         else
  813.         v1 %= v2;
  814.         break;
  815.  
  816.     case OP_ASL:
  817.         v1 <<= v2;
  818.         break;
  819.  
  820.     case OP_ASR:
  821.         v1 >>= v2;
  822.         break;
  823.  
  824.     case OP_AND:
  825.         v1 &= v2;
  826.         break;
  827.  
  828.     case OP_OR:
  829.         v1 |= v2;
  830.         break;
  831.  
  832.     case OP_XOR:
  833.         v1 ^= v2;
  834.         break;
  835.  
  836.     case OP_EQ:
  837.         v1 = (v1 == v2);
  838.         break;
  839.  
  840.     case OP_NE:
  841.         v1 = (v1 != v2);
  842.         break;
  843.  
  844.     case OP_LT:
  845.         v1 = (v1 < v2);
  846.         break;
  847.  
  848.     case OP_LE:
  849.         v1 = (v1 <= v2);
  850.         break;
  851.  
  852.     case OP_GE:
  853.         v1 = (v1 >= v2);
  854.         break;
  855.  
  856.     case OP_GT:
  857.         v1 = (v1 > v2);
  858.         break;
  859.  
  860.     case OP_ANA:
  861.         v1 = (v1 && v2);
  862.         break;
  863.  
  864.     case OP_ORO:
  865.         v1 = (v1 || v2);
  866.         break;
  867.  
  868.     case OP_COL:
  869.         /*
  870.          * v1 has the "true" value, v2 the "false" value.
  871.          * The top of the value stack has the test.
  872.          */
  873.         v1 = (*--valp) ? v1 : v2;
  874.         break;
  875.  
  876.     case OP_NEG:
  877.         v1 = (-v1);
  878.         break;
  879.  
  880.     case OP_PLU:
  881.         break;
  882.  
  883.     case OP_COM:
  884.         v1 = ~v1;
  885.         break;
  886.  
  887.     case OP_NOT:
  888.         v1 = !v1;
  889.         break;
  890.  
  891.     default:
  892.         cierror("#if bug, operand = %d.", op);
  893.         v1 = 0;
  894.     }
  895.     *valp++ = v1;
  896.     return (valp);
  897. }
  898.  
  899. #ifdef    DEBUG_EVAL
  900. dumpstack(opstack, opp, value, valp)
  901. OPTAB        opstack[NEXP];    /* Operand stack        */
  902. register OPTAB    *opp;        /* Operator stack        */
  903. int        value[NEXP];    /* Value stack            */
  904. register int    *valp;        /* -> value vector        */
  905. {
  906.     printf("index op prec skip name -- op stack at %s", infile->bptr);
  907.     while (opp > opstack) {
  908.         printf(" [%2d] %2d  %03o    %d %s\n", opp - opstack,
  909.         opp->op, opp->prec, opp->skip, opname[opp->op]);
  910.         opp--;
  911.     }
  912.     while (--valp >= value) {
  913.         printf("value[%d] = %d\n", (valp - value), *valp);
  914.     }
  915. }
  916. #endif
  917.  
  918.